home *** CD-ROM | disk | FTP | other *** search
/ CD-ROM Today - The Disc! 5 / CD-ROM Today - The Disc (Issue 5)(November 1994).ISO / mac / Mac shareware / Education / RLaB / rlib / plplot.r < prev    next >
Encoding:
Text File  |  1994-09-21  |  41.2 KB  |  1,832 lines  |  [TEXT/ttxt]

  1.  
  2. #
  3. # New plot.r for use with PLPLOT library.
  4. # The help files for these functions are in
  5. # misc/plhelp
  6. #
  7.  
  8. # plplot.r
  9.  
  10. #  This file is a part of RLaB ("Our"-LaB)
  11. #  Copyright (C) 1994  Ian R. Searle
  12.  
  13. #  This program is free software; you can redistribute it and/or modify
  14. #  it under the terms of the GNU General Public License as published by
  15. #  the Free Software Foundation; either version 2 of the License, or
  16. #  (at your option) any later version.
  17.  
  18. #  This program is distributed in the hope that it will be useful,
  19. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21. #  GNU General Public License for more details.
  22.  
  23. #  You should have received a copy of the GNU General Public License
  24. #  along with this program; if not, write to the Free Software
  25. #  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  26.  
  27. #  See the file ../COPYING
  28.  
  29.  
  30. static (WIN)            # The static plot window structure
  31. static (P)            # The active/current plot window
  32.  
  33. static (create_plot_object)
  34. static (check_plot_object)
  35. static (xy_scales)
  36. static (xyz_scales)
  37. static (list_scales)
  38. static (hist_scales)
  39. static (plot_matrix)
  40. static (plot_list)
  41. static (check_3d_list)
  42. static (find_char)
  43. static (get_style)
  44. static (make_legend)
  45.  
  46. static (plhold_first)
  47.  
  48. #
  49. # Defaults
  50. #
  51.  
  52. static (grid_x_default, grid_y_default)
  53. static (grid_3x_default, grid_3y_default, grid_3z_default)
  54.  
  55. grid_x_default = "bcgnst";
  56. grid_y_default = "bcgnstv";
  57. grid_3x_default = "bnstu";
  58. grid_3y_default = "bnstu";
  59. grid_3z_default = "bcdmnstuv";
  60.  
  61. #
  62. # Create the default plot-object.
  63. # Initialize to all the default values
  64. #
  65.  
  66. WIN = <<>>;    # Create the plot-object list
  67.  
  68. create_plot_object = function ( N, nx, ny )
  69. {
  70.   local (i, j, pobj)
  71.   
  72.   if (!exist (N)) { N = 0; }
  73.   
  74.   pobj = <<>>;
  75.   pobj.subplot = 0;        # The current subplot no.
  76.   pobj.nplot = nx*ny;        # Total no. of plots on window
  77.   
  78.   pobj.fontld = 0;        # Loaded extended fonts?
  79.   
  80.   for (i in 1:(nx*ny))
  81.   {
  82.     pobj.style.[i] = "line";    # The type/style of plot to draw
  83.     pobj.pstyle[i] = 1;            # The point-style
  84.     pobj.nbin[i] = inf();    # The number of bins for a histogram
  85.     pobj.width[i] = 1;        # The pen width for current plot
  86.     pobj.font[i] = 1;        # The current font
  87.     pobj.xlabel[i] = "";
  88.     pobj.ylabel[i] = "";
  89.     pobj.zlabel[i] = "";
  90.     pobj.title[i] = "";
  91.     pobj.orientation[i] = "portrait";
  92.     pobj.desc.[i] = "default";        # The legend description
  93.     pobj.gridx[i] =  grid_x_default;    # Plot axes style, 2D-X
  94.     pobj.gridy[i] =  grid_y_default;    # Plot axes style, 2D-Y
  95.     pobj.grid3x[i] = grid_3x_default;    # Plot axes style, 3D-X
  96.     pobj.grid3y[i] = grid_3y_default;    # Plot axes style, 3D-Y
  97.     pobj.grid3z[i] = grid_3z_default;    # Plot axes style, 3D-Z
  98.     pobj.aspect[i] = 0;        # Plot aspect style
  99.     pobj.alt[i] = 60;
  100.     pobj.az[i] = 45;
  101.     
  102.     pobj.xmin[i] = inf();
  103.     pobj.xmax[i] = inf();
  104.     pobj.ymin[i] = inf();
  105.     pobj.ymax[i] = inf();
  106.     pobj.zmin[i] = inf();
  107.     pobj.zmax[i] = inf();
  108.     
  109.     for (j in 1:14) { pobj.color[i;j] = j; }       
  110.     for (j in 1:8)  { pobj.lstyle[i;j] = j; }
  111.   }
  112.   
  113.   #
  114.   # Save and return the newly generated plot-object
  115.   #
  116.   
  117.   WIN.[N] = pobj;
  118.   //return WIN.[N];
  119. };
  120.  
  121. #
  122. # Check to make sure a plot-object exists. If one
  123. # does not exist, create it.
  124. #
  125.  
  126. check_plot_object = function ()
  127. {
  128.   if (length (WIN) == 0)
  129.   {
  130.     pstart();
  131.     return 0;
  132.   }
  133.   return 1;
  134. };
  135.  
  136. #
  137. # Set the current plot window
  138. # Default value = 0
  139. #
  140.  
  141. pwin = function ( N )
  142. {
  143.   check_plot_object ();
  144.   if (!exist (N)) { N = 0; }
  145.   
  146.   # Check to make sure N is valid
  147.   
  148.   for (i in members (WIN))
  149.   {
  150.     if (N == strtod (i))
  151.     {
  152.       _plsstrm (N);
  153.       return P = N;
  154.     }
  155.   }
  156.   printf ("pwin: invalid argument, N = %i\n", N);
  157.   printf ("      valid values are:\n");
  158.   WIN?
  159. };
  160.  
  161. showpwin = function ()
  162. {
  163.   check_plot_object ();
  164.   
  165.   printf ("Curren plot-window is: %i\n", P);
  166.   printf ("Available plot windows are:\n");
  167.   WIN?
  168. };
  169.  
  170. #
  171. # Set/start/select the plot device
  172. #
  173.  
  174. pstart = function ( nx, ny, dev )
  175. {
  176.   if (!exist (nx)) { nx = 1; }
  177.   if (!exist (ny)) { ny = 1; }
  178.   if (!exist (dev)) { dev = "?"; }
  179.   
  180.   # Create the plot-object
  181.   # First, figure out the index
  182.   if (!exist (P))
  183.   {
  184.     P = 0;
  185.   else
  186.     P = P + 1;
  187.   }
  188.   
  189.   create_plot_object (P, nx, ny);
  190.   _plsstrm (P);
  191.   
  192.   #_plscolbg (255,255,255); # white
  193.   # Default window size for X
  194.   _plspage (0, 0, 400, 300, 200, 200);
  195.   
  196.   # Start up the plot-window
  197.   _plstart (dev, nx, ny);
  198.   
  199.   _plwid (8);
  200.   
  201.   # Turn between plot pause off
  202.   _plspause (0);
  203.   _pltext ();
  204.   
  205.   return P;
  206. };
  207.  
  208. #
  209. # Close a plot device. We must destroy the current plot-object
  210. # And switch the output stream back to the default.
  211. #
  212.  
  213. pclose = function ()
  214. {
  215.   local (n)
  216.   if (size (WIN) > 1)
  217.   {   
  218.     clear (WIN.[P]);
  219.     _plend1 ();
  220.     _plsstrm (strtod (members (WIN)[1]));
  221.     P = strtod (members (WIN)[1]);
  222.   else
  223.     if (exist (WIN.[P])) { clear (WIN.[P]); }
  224.     _plend1 ();
  225.   }
  226. };
  227.  
  228. #
  229. # Close ALL the plot-windows
  230. #
  231.  
  232. pend = function ()
  233. {
  234.   _plend ();
  235.   if (exist (WIN)) { clear (WIN); }
  236.   if (exist (P)) { clear (P); }
  237.   WIN = <<>>;
  238. };
  239.  
  240. ##############################################################################
  241. #
  242. # Plot the columns of a matrix (X-Y plot).
  243. #
  244. ##############################################################################
  245.  
  246. plot = function ( data )
  247. {
  248.   local (hscale, xmin, xmax, ymin, ymax, i, p)
  249.   
  250.   check_plot_object ();
  251.   
  252.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  253.   
  254.   #
  255.   # Draw the graph
  256.   # Step through the matrix plotting
  257.   # each column versus the 1st
  258.   #
  259.   
  260.   if (class (data) == "num")
  261.   {
  262.     _plgra ();
  263.     _plcol (1);
  264.     _pllsty (1);
  265.     _plfont (WIN.[P].font[p]);
  266.     _plwid (WIN.[P].width[p]);
  267.     xy_scales ( real(data), p, xmin, xmax, ymin, ymax );
  268.     
  269.     _pladv (0);
  270.     _plvsta ();
  271.     _plwind (xmin, xmax, ymin, ymax);
  272.     _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  273.     if (plot_matrix ( data, p, 0, xmin, xmax, ymin, ymax, ymax-ymin ) < 0) 
  274.     {
  275.       return -1;
  276.     }
  277.     
  278.     else if (class (data) == "list") {
  279.       
  280.       _plgra ();
  281.       _plcol (1);
  282.       _pllsty (1);
  283.       _plfont (WIN.[P].font[p]);
  284.       _plwid (WIN.[P].width[p]);
  285.       list_scales ( data , p, xmin, xmax, ymin, ymax );
  286.       _pladv (0);
  287.       _plvsta ();
  288.       _plwind (xmin, xmax, ymin, ymax);
  289.       _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  290.       if (plot_list ( data, p, xmin, xmax, ymin, ymax ) < 0) 
  291.       { 
  292.     return -1;
  293.       }
  294.  
  295.     else
  296.       error ("plot: un-acceptable argument");
  297.   } }
  298.  
  299.   _pllsty (1);
  300.   _plcol (1);
  301.   _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);  
  302.   _plflush ();
  303.   _pltext ();
  304.   
  305.   #
  306.   # Increment the plot no. so that next time
  307.   # we use the correct settings.
  308.   #
  309.   
  310.   WIN.[P].subplot = WIN.[P].subplot + 1;
  311.   return P;
  312. };
  313.  
  314. #
  315. # plhold:
  316. # Plot some data, and "hold" on for more.
  317. # Plot the data, setting up the plot as usual the first time.
  318. # On subsequent plots do not do any setup, just plot some
  319. # more. plhold_off must be called to finish up.
  320. #
  321.  
  322. plhold_first = 1;    # True (1) if plhold() has NOT been used.
  323.                         # Or if plhold_off() has been used.
  324.             # False (0) if plhold is in use
  325.  
  326. static (hxmin, hxmax, hymin, hymax)
  327.  
  328. plhold = function ( data )
  329. {
  330.   local (hscale, xmin, xmax, ymin, ymax, i, p)
  331.   
  332.   check_plot_object ();
  333.   
  334.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  335.   
  336.   if (plhold_first)
  337.   {
  338.     if (class (data) == "num")
  339.     {
  340.       #
  341.       # Do the setup ONCE
  342.       #
  343.       hxmin = hxmax = hymin = hymax = 0;
  344.       _plgra ();
  345.       _plcol (1);
  346.       _pllsty (1);
  347.       _plfont (WIN.[P].font[p]);
  348.       _plwid (WIN.[P].width[p]);
  349.       xy_scales ( real(data), p, hxmin, hxmax, hymin, hymax );
  350.       
  351.       _pladv (0);
  352.       _plvsta ();
  353.       _plwind (hxmin, hxmax, hymin, hymax);
  354.       _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  355.       _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);
  356.     else
  357.       error ("plot: un-acceptable argument");
  358.     }
  359.     plhold_first = 0;
  360.   }
  361.   
  362.   if (plot_matrix ( data, p, 0, hxmin, hxmax, hymin, hymax, hymax-hymin ) < 0) 
  363.   { 
  364.     return -1; 
  365.   }
  366.  
  367.   _plcol (1);
  368.   _plflush ();
  369.   
  370.   return P;
  371. };
  372.  
  373. plhold_off = function ( )
  374. {
  375.   local (p)
  376.   
  377.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  378.   plhold_first = 1;  
  379.   _plcol (1);
  380.   _plflush ();
  381.   WIN.[P].subplot = WIN.[P].subplot + 1;
  382.   return P;
  383. };
  384.  
  385. ##############################################################################
  386. #
  387. # Plot a 3-Dimensional graph. The data is composed in a list, with
  388. # elements `x', `y', and `z'. x and y are single-dimension arrays
  389. # (row or column matrices), and z is a two-dimensional array. The
  390. # array z, is a function of x and y: z = f(x,y). Thus, the values in
  391. # the array x can be thought of a "row-labels", and the values of y
  392. # can be thought of as "column-lables" for the 2-dimensioal array z.
  393. #
  394. # At present plot3 can plot 3 distinct lists. Each list may have
  395. # different X, Y, and Z scales.
  396. #
  397. ##############################################################################
  398.  
  399. plot3 = function ( L31, L32, L33 )
  400. {
  401.   local (p, xmin, xmax, ymin, ymax, zmin, zmax, basex, basey, height, ...
  402.          xmin2d, xmax2d, ymin2d, ymax2d, alt, az, ...
  403.          Xmin, Xmax, Ymin, Ymax, Zmin, Zmax)
  404.  
  405.   check_plot_object ();
  406.  
  407.   #
  408.   # 1st check list contents
  409.   #
  410.   
  411.   if (exist (L31)) { check_3d_list (L31); }
  412.   if (exist (L32)) { check_3d_list (L32); }
  413.   if (exist (L33)) { check_3d_list (L33); }
  414.   
  415.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  416.  
  417.   #
  418.   # Figure out the scale limits. 
  419.   # Needs improvement!
  420.   #
  421.   
  422.   xmin = xmax = ymin = ymax = zmin = zmax = 0;
  423.   if (exist (L31)) 
  424.   {
  425.     xyz_scales (L31, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  426.     if (Xmin < xmin) { xmin = Xmin; } if (Xmax > xmax) { xmax = Xmax; }
  427.     if (Ymin < ymin) { ymin = Ymin; } if (Ymax > ymax) { ymax = Ymax; }
  428.     if (Zmin < zmin) { zmin = Zmin; } if (Zmax > zmax) { zmax = Zmax; }
  429.   }
  430.   if (exist (L32)) 
  431.   {
  432.     xyz_scales (L32, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  433.     if (Xmin < xmin) { xmin = Xmin; } if (Xmax > xmax) { xmax = Xmax; }
  434.     if (Ymin < ymin) { ymin = Ymin; } if (Ymax > ymax) { ymax = Ymax; }
  435.     if (Zmin < zmin) { zmin = Zmin; } if (Zmax > zmax) { zmax = Zmax; }
  436.   }   
  437.   if (exist (L33)) 
  438.   {
  439.     xyz_scales (L33, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  440.     if (Xmin < xmin) { xmin = Xmin; } if (Xmax > xmax) { xmax = Xmax; }
  441.     if (Ymin < ymin) { ymin = Ymin; } if (Ymax > ymax) { ymax = Ymax; }
  442.     if (Zmin < zmin) { zmin = Zmin; } if (Zmax > zmax) { zmax = Zmax; }
  443.   }
  444.   
  445.   _plgra ();
  446.   _plcol (1);
  447.   _pllsty (1);
  448.   _plfont (WIN.[P].font[p]);
  449.   _plwid (WIN.[P].width[p]);
  450.   
  451.   basex = 2; basey = 2; height = 4;
  452.   xmin2d = -2.0; xmax2d = 2.0;
  453.   ymin2d = -2.5; ymax2d = 5.0;
  454.   
  455.   _plenv (xmin2d, xmax2d, ymin2d, ymax2d, 0, -2);
  456.   _plw3d (basex, basey, height, xmin, xmax, ymin, ymax, ...
  457.           zmin, zmax, WIN.[P].alt[p], WIN.[P].az[p]);
  458.   _plbox3 (WIN.[P].grid3x[p], WIN.[P].xlabel[p], 0, 0, ...
  459.            WIN.[P].grid3y[p], WIN.[P].ylabel[p], 0, 0, ...
  460.            WIN.[P].grid3z[p], WIN.[P].zlabel[p], 0, 0);
  461.   _plmtex ("t", 1.0, 0.5, 0.5, WIN.[P].title[p]);
  462.  
  463.   if (exist (L31))
  464.   {
  465.     _plcol (2);
  466.     _plot3d (real(L31.x), real(L31.y), real(L31.z), ...
  467.              L31.x.n, L31.y.n, 3, 0);
  468.   }
  469.   if (exist (L32))
  470.   {
  471.     _plcol (3);
  472.     _pllsty (2);
  473.     _plot3d (real(L32.x), real(L32.y), real(L32.z), ...
  474.              L32.x.n, L32.y.n, 3, 0);
  475.   }
  476.   if (exist (L33)) 
  477.   {
  478.     _plcol (4);
  479.     _pllsty (3);
  480.     _plot3d (real(L33.x), real(L33.y), real(L33.z), ...
  481.              L33.x.n, L33.y.n, 3, 0);
  482.   }
  483.   
  484.   _plflush ();
  485.   _pltext ();
  486.   
  487.   #
  488.   # Increment the plot no. so that next time
  489.   # we use the correct settings.
  490.   #
  491.   
  492.   WIN.[P].subplot = WIN.[P].subplot + 1;
  493.   
  494.   return P;
  495. };
  496.  
  497. ##############################################################################
  498. #
  499. # Plot a 3-Dimensional graph. The data is composed in a list, with
  500. # elements `x', `y', and `z'. x and y are single-dimension arrays
  501. # (row or column matrices), and z is a two-dimensional array. The
  502. # array z, is a function of x and y: z = f(x,y). Thus, the values in
  503. # the array x can be thought of a "row-labels", and the values of y
  504. # can be thought of as "column-lables" for the 2-dimensioal array z.
  505. #
  506. # At present plmesh can plot 3 distinct lists. Each list may have
  507. # different X, Y, and Z scales.
  508. #
  509. ##############################################################################
  510.  
  511. plmesh = function ( L31, L32, L33 )
  512. {
  513.   local (p, xmin, xmax, ymin, ymax, zmin, zmax, basex, basey, height, ...
  514.          xmin2d, xmax2d, ymin2d, ymax2d, alt, az, ...
  515.          Xmin, Xmax, Ymin, Ymax, Zmin, Zmax)
  516.  
  517.   check_plot_object ();
  518.   
  519.   #
  520.   # 1st check list contents
  521.   #
  522.   
  523.   if (exist (L31)) { check_3d_list (L31); }
  524.   if (exist (L32)) { check_3d_list (L32); }
  525.   if (exist (L33)) { check_3d_list (L33); }
  526.   
  527.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  528.  
  529.   #
  530.   # Figure out the scale limits. 
  531.   # Needs improvement!
  532.   #
  533.   
  534.   xmin = xmax = ymin = ymax = zmin = zmax = 0;
  535.   if (exist (L31)) 
  536.   {
  537.     xyz_scales (L31, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  538.     if (Xmin < xmin) { xmin = Xmin; } if (Xmax > xmax) { xmax = Xmax; }
  539.     if (Ymin < ymin) { ymin = Ymin; } if (Ymax > ymax) { ymax = Ymax; }
  540.     if (Zmin < zmin) { zmin = Zmin; } if (Zmax > zmax) { zmax = Zmax; }
  541.   }
  542.   if (exist (L32)) 
  543.   {
  544.     xyz_scales (L32, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  545.     if (Xmin < xmin) { xmin = Xmin; } if (Xmax > xmax) { xmax = Xmax; }
  546.     if (Ymin < ymin) { ymin = Ymin; } if (Ymax > ymax) { ymax = Ymax; }
  547.     if (Zmin < zmin) { zmin = Zmin; } if (Zmax > zmax) { zmax = Zmax; }
  548.   }   
  549.   if (exist (L33)) 
  550.   {
  551.     xyz_scales (L33, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  552.     if (Xmin < xmin) { xmin = Xmin; } if (Xmax > xmax) { xmax = Xmax; }
  553.     if (Ymin < ymin) { ymin = Ymin; } if (Ymax > ymax) { ymax = Ymax; }
  554.     if (Zmin < zmin) { zmin = Zmin; } if (Zmax > zmax) { zmax = Zmax; }
  555.   }
  556.  
  557.   _plgra ();
  558.   _plcol (1);
  559.   _pllsty (1);
  560.   _plfont (WIN.[P].font[p]);
  561.   _plwid (WIN.[P].width[p]);
  562.   
  563.   basex = 2; basey = 2; height = 4;
  564.   xmin2d = -2.0; xmax2d = 2.0;
  565.   ymin2d = -2.5; ymax2d = 5.0;
  566.   
  567.   _plenv (xmin2d, xmax2d, ymin2d, ymax2d, 0, -2);
  568.   _plw3d (basex, basey, height, xmin, xmax, ymin, ymax, ...
  569.           zmin, zmax, WIN.[P].alt[p], WIN.[P].az[p]);
  570.   _plbox3 (WIN.[P].grid3x[p], WIN.[P].xlabel[p], 0, 0, ...
  571.            WIN.[P].grid3y[p], WIN.[P].ylabel[p], 0, 0, ...
  572.            WIN.[P].grid3z[p], WIN.[P].zlabel[p], 0, 0);
  573.   _plmtex ("t", 1.0, 0.5, 0.5, WIN.[P].title[p]);
  574.  
  575.   if (exist (L31))
  576.   {
  577.     _plcol (2);
  578.     _plmesh (real(L31.x), real(L31.y), real(L31.z), ...
  579.              L31.x.n, L31.y.n, 3);
  580.   }
  581.   if (exist (L32))
  582.   {
  583.     _plcol (3);
  584.     _pllsty (2);
  585.     _plmesh (real(L32.x), real(L32.y), real(L32.z), ...
  586.              L32.x.n, L32.y.n, 3);
  587.   }
  588.   if (exist (L33)) 
  589.   {
  590.     _plcol (4);
  591.     _pllsty (3);
  592.     _plmesh (real(L33.x), real(L33.y), real(L33.z), ...
  593.              L33.x.n, L33.y.n, 3);
  594.   }
  595.  
  596.   _plflush ();
  597.   _pltext ();
  598.   
  599.   #
  600.   # Increment the plot no. so that next time
  601.   # we use the correct settings.
  602.   #
  603.   
  604.   WIN.[P].subplot = WIN.[P].subplot + 1;
  605.   
  606.   return P;
  607. };
  608.  
  609. ##############################################################################
  610. #
  611. # Plot contours. The data is composed in a list, with
  612. # elements `x', `y', and `z'. x and y are single-dimension arrays
  613. # (row or column matrices), and z is a two-dimensional array. The
  614. # array z, is a function of x and y: z = f(x,y). Thus, the values in
  615. # the array x can be thought of a "row-labels", and the values of y
  616. # can be thought of as "column-lables" for the 2-dimensioal array z.
  617. #
  618. ##############################################################################
  619.  
  620. plcont = function ( CL )
  621. {
  622.   local (p, xmin, xmax, ymin, ymax, zmin, zmax, ...
  623.          Xmin, Xmax, Ymin, Ymax, Zmin, Zmax, i, v, ...
  624.          xl, yl, clevel, k, j)
  625.      
  626.   check_plot_object ();
  627.  
  628.   #
  629.   # 1st check list contents
  630.   #
  631.   
  632.   if (exist (CL)) { check_3d_list (CL); }
  633.  
  634.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  635.   
  636.   #
  637.   # Figure out the scale limits. 
  638.   # Needs improvement!
  639.   #
  640.  
  641.   xmin = xmax = ymin = ymax = zmin = zmax = 0;
  642.   if (exist (CL)) 
  643.   {
  644.     xyz_scales (CL, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  645.     if (Xmin < xmin) { xmin = Xmin; } if (Xmax > xmax) { xmax = Xmax; }
  646.     if (Ymin < ymin) { ymin = Ymin; } if (Ymax > ymax) { ymax = Ymax; }
  647.     if (Zmin < zmin) { zmin = Zmin; } if (Zmax > zmax) { zmax = Zmax; }
  648.   }
  649.  
  650.   _plgra ();
  651.   _plcol (1);
  652.   _pllsty (1);
  653.   _plfont (WIN.[P].font[p]);
  654.   _plwid (WIN.[P].width[p]);
  655.  
  656.   #
  657.   # Set up the 1st viewport for drawing the plot.
  658.   #
  659.  
  660.   _pladv (0);
  661.   _plvpor (0.15, 0.75, 0.15, 0.85);
  662.   _plwind (xmin, xmax, ymin, ymax);
  663.   _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  664.  
  665.   if (exist (CL.clevel))
  666.   {
  667.     clevel = CL.clevel;
  668.   else
  669.     clevel = linspace(zmin, zmax, 10);
  670.   }
  671.  
  672.   #
  673.   # Draw the contours
  674.   #
  675.  
  676.   for (i in 1:clevel.n)
  677.   {
  678.     k = mod (i-1, 14) + 1;
  679.     j = mod (i-1, 8) + 1;
  680.     _pllsty(j);
  681.     _plcol (1+k);
  682.     _plcont (CL.x, CL.y, CL.z, 1, CL.x.n, 1, CL.y.n, clevel[i]);
  683.   }
  684.  
  685.   #
  686.   # Reset color and draw the labels.
  687.   #
  688.  
  689.   _plcol (1);
  690.   _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);  
  691.  
  692.   #
  693.   # Draw the contour legend. Use a new viewport to the right
  694.   # of the contour plot.
  695.   #
  696.  
  697.   _plvpor (0.75, 1.0, 0.15, 0.85);
  698.   _plwind (0, 1, 0, 1);
  699.  
  700.   v = 1 - 1/(2*clevel.n);
  701.  
  702.   for (i in 1:clevel.n)
  703.   {
  704.     xl = [0.1, 0.2, 0.3]';
  705.     yl = [v, v, v]';
  706.     v = v - 1/clevel.n;
  707.  
  708.     k = mod (i-1, 14) + 1;
  709.     j = mod (i-1, 8) + 1;
  710.  
  711.     _plcol (1+k);
  712.     _pllsty (j);
  713.  
  714.     _plline (3, xl, yl);
  715.     plptex (num2str (clevel[i]), xl[3]+.1, yl[3], , , 0);
  716.   }
  717.  
  718.   # Flush  and go back to text mode.
  719.   _plflush ();
  720.   _pltext ();
  721.   
  722.   #
  723.   # Increment the plot no. so that next time
  724.   # we use the correct settings.
  725.   #
  726.   
  727.   WIN.[P].subplot = WIN.[P].subplot + 1;
  728.   
  729.   return P;
  730. };
  731.  
  732. ##############################################################################
  733. #
  734. # Plot a Histogram(s), from the columns of a matrix.
  735. #
  736. ##############################################################################
  737.  
  738. plhist = function ( M , nbin )
  739. {
  740.   local (hscale, i, k, np, p, ymin, ymax, xmax, v, xl, yl, desc)
  741.  
  742.   check_plot_object ();
  743.   
  744.   if (!exist (nbin)) { nbin = 10; }
  745.   
  746.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  747.   np = M.nr;
  748.   
  749.   # Compute max/min values of data
  750.   
  751.   ymin = min (min (real (M)));
  752.   ymax = max (max (real (M)));
  753.   
  754.   #
  755.   # Check computed scale limits against user's
  756.   #
  757.   
  758.   if (!isinf (WIN.[P].ymin[p])) { ymin = WIN.[P].ymin[p]; }
  759.   if (!isinf (WIN.[P].ymax[p])) { ymax = WIN.[P].ymax[p]; }
  760.  
  761.   _plgra ();
  762.   _plcol (1);
  763.   _plfont (WIN.[P].font[p]);
  764.   _plwid (WIN.[P].width[p]);
  765.   
  766.   for (i in 1:M.nc) 
  767.   { 
  768.     hscale[i] = hist_scales (M[;i], nbin);
  769.   }  
  770.  
  771.   _pladv (0);
  772.   _plvsta ();
  773.   _plwind (ymin, ymax, 0, max (hscale));
  774.   _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  775.  
  776.   v = max (hscale);
  777.   xmax = ymax;
  778.   for (i in 1:M.nc)
  779.   {
  780.     k = mod (i, 14) + 1;
  781.     _plcol (WIN.[P].color[p;k]);
  782.     _plhist (np, real(M[;i]), ymin, ymax, nbin, 1);
  783.     
  784.     if (!any (any (isinf (WIN.[P].desc.[p]))))
  785.     {
  786.       # Use the default if necessary
  787.       if (WIN.[P].desc.[p][1] == "default") 
  788.       {
  789.     desc = "c1";
  790.     else if (WIN.[P].desc.[p].n >= i) {
  791.       desc = WIN.[P].desc.[p][i];
  792.     else
  793.       # Not sure what to do, user has messed up.
  794.       desc = "";
  795.       } }
  796.       
  797.       v = v - max(hscale)/11;
  798.       xl = (ymax-ymin)*[10.5/12, 11/12, 11.5/12]' + ymin;
  799.       yl = [v, v, v]';
  800.  
  801.       _plline (3, xl, yl);
  802.       plptex(desc, xl[1]-(ymax-ymin)/25, yl[3], , , 1);
  803.     }
  804.   }
  805.  
  806.   _plcol (1);
  807.   _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);  
  808.   _plflush ();
  809.   _pltext ();
  810.  
  811.   #
  812.   # Increment the plot no. so that next time
  813.   # we use the correct settings.
  814.   #
  815.   
  816.   WIN.[P].subplot = WIN.[P].subplot + 1;
  817.  
  818.   return 1;
  819. };
  820.  
  821. ##############################################################################
  822. #
  823. # Various support functions for the WIN list
  824. #
  825. ##############################################################################
  826.  
  827. #
  828. # Replot
  829. #
  830.  
  831. replot = function ( )
  832. {
  833.   check_plot_object ();
  834.   _replot ();
  835. };
  836.  
  837. #
  838. # Set the X-axis label
  839. #
  840.  
  841. xlabel = function ( xstr )
  842. {
  843.   local (i);
  844.   
  845.   check_plot_object ();
  846.   if (!exist (xstr)) { xstr = ""; }
  847.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  848.   WIN.[P].xlabel[i] = xstr;
  849. };
  850.  
  851. #
  852. # Set the Y-axis label
  853. #
  854.  
  855. ylabel = function ( xstr )
  856. {
  857.   local (i);
  858.   
  859.   check_plot_object ();
  860.   if (!exist (xstr)) { xstr = ""; }
  861.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  862.   WIN.[P].ylabel[i] = xstr;
  863. };
  864.  
  865. #
  866. # Set the Z-axis label
  867. #
  868.  
  869. zlabel = function ( xstr )
  870. {
  871.   local (i);
  872.   
  873.   check_plot_object ();
  874.   if (!exist (xstr)) { xstr = ""; }
  875.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  876.   WIN.[P].zlabel[i] = xstr;
  877. };
  878.  
  879. #
  880. # Set the plot-title
  881. #
  882.  
  883. ptitle = function ( xstr )
  884. {
  885.   local (p);
  886.   
  887.   check_plot_object ();
  888.   if (!exist (xstr)) { xstr = ""; }
  889.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  890.   WIN.[P].title[p] = xstr;
  891. };
  892.  
  893. plimits = function ( xmin, xmax, ymin, ymax, zmin, zmax )
  894. {
  895.   local (i);
  896.  
  897.   check_plot_object ();
  898.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  899.   if (exist (xmin)) {
  900.     WIN.[P].xmin[i] = xmin;
  901.   else
  902.     WIN.[P].xmin[i] = inf ();
  903.   }
  904.   if (exist (xmax)) { 
  905.     WIN.[P].xmax[i] = xmax;
  906.   else
  907.     WIN.[P].xmax[i] = inf ();
  908.   }
  909.   if (exist (ymin)) {
  910.     WIN.[P].ymin[i] = ymin;
  911.   else
  912.     WIN.[P].ymin[i] = inf ();
  913.   }
  914.   if (exist (ymax)) {
  915.     WIN.[P].ymax[i] = ymax;
  916.   else
  917.     WIN.[P].ymax[i] = inf ();
  918.   }
  919.   if (exist (zmin)) {
  920.     WIN.[P].zmin[i] = zmin;
  921.   else
  922.     WIN.[P].zmin[i] = inf ();
  923.   }
  924.   if (exist (zmax)) {
  925.     WIN.[P].zmax[i] = zmax;
  926.   else
  927.     WIN.[P].zmax[i] = inf ();
  928.   }
  929. };
  930.  
  931. plgrid = function ( sty_x, sty_y )
  932. {
  933.   local (i)
  934.  
  935.   check_plot_object ();
  936.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  937.  
  938.   if (exist (sty_x)) 
  939.   { 
  940.     if (class (sty_x) == "string")
  941.     {
  942.       WIN.[P].gridx[i] = sty_x;
  943.     else
  944.       error ("plgrid: requires string argument GRID_STY_X");
  945.     }
  946.   else
  947.     WIN.[P].gridx[i] = grid_x_default;
  948.   }
  949.   if (exist (sty_y)) 
  950.   { 
  951.     if (class (sty_y) == "string")
  952.     {
  953.       WIN.[P].gridy[i] = sty_y;
  954.     else
  955.       error ("plgrid: requires string argument GRID_STY_Y");
  956.     }
  957.   else
  958.     WIN.[P].gridy[i] = grid_y_default;
  959.   }
  960. };
  961.  
  962.  plgrid3 = function ( sty_x, sty_y, sty_z )
  963.  {
  964.    local (i)
  965.  
  966.    check_plot_object ();
  967.    i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  968.    if (exist (sty_x)) 
  969.    { 
  970.      if (class (sty_x) == "string")
  971.      {
  972.        WIN.[P].grid3x[i] = sty_x;
  973.      else
  974.        error ("plgrid3: requires string argument GRID_STY_X");
  975.      }
  976.    else
  977.      WIN.[P].grid3x[i] = grid_3x_default;
  978.    }
  979.    if (exist (sty_y)) 
  980.    { 
  981.      if (class (sty_y) == "string")
  982.      {
  983.        WIN.[P].grid3y[i] = sty_y;
  984.      else
  985.        error ("plgrid3: requires string argument GRID_STY_Y");
  986.      }
  987.    else
  988.      WIN.[P].grid3y[i] = grid_3y_default;
  989.    }
  990.    if (exist (sty_z)) 
  991.    { 
  992.      if (class (sty_z) == "string")
  993.      {
  994.        WIN.[P].grid3z[i] = sty_z;
  995.      else
  996.        error ("plgrid3: requires string argument GRID_STY_Z");
  997.      }
  998.    else
  999.      WIN.[P].grid3z[i] = grid_3z_default;
  1000.    }
  1001.  };
  1002.  
  1003.  #
  1004.  # A friendlier interface to changing grid/axis
  1005.  # styles.
  1006.  #
  1007.  
  1008.  plaxis = function ( X_STR, Y_STR )
  1009.  {
  1010.    local (i)
  1011.  
  1012.    check_plot_object ();
  1013.    i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1014.  
  1015.    if (exist (X_STR))
  1016.    {
  1017.      if (X_STR == "log") { WIN.[P].gridx[i] = "bcngstl"; }
  1018.    else
  1019.      WIN.[P].gridx[i] = grid_x_default;
  1020.    }
  1021.  
  1022.    if (exist (Y_STR))
  1023.    {
  1024.      if (Y_STR == "log") { WIN.[P].gridy[i] = "bcngstlv"; }
  1025.    else
  1026.      WIN.[P].gridy[i] = grid_y_default;
  1027.    }
  1028.    return P;
  1029.  };
  1030.  
  1031.  #
  1032.  # Change plot aspect ratio
  1033.  #
  1034.  
  1035.  plaspect = function ( style )
  1036.  {
  1037.    local (i)
  1038.  
  1039.    check_plot_object ();
  1040.    i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1041.    if (exist (style)) { WIN.[P].aspect[i] = style; }
  1042.  };
  1043.  
  1044.  #
  1045.  # Change plot line style
  1046.  #
  1047.  
  1048.  plstyle = function ( style )
  1049.  {
  1050.    local (i)
  1051.  
  1052.    check_plot_object ();
  1053.    i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1054.    if (exist (style)) 
  1055.    {
  1056.      if (class (style) == "string") 
  1057.      {
  1058.        WIN.[P].style.[i] = style;
  1059.      }
  1060.      return 1;
  1061.    }
  1062.    WIN.[P].style[i] = "line";  
  1063.  };
  1064.  
  1065.  #
  1066.  # Get the right value of line-style
  1067.  #
  1068.  
  1069.  get_style = function ( STY, K )
  1070.  {
  1071.    local (sty);
  1072.    sty = mod(K, STY.n);
  1073.    if(sty == 0) { sty = STY.n; }
  1074.    return STY[sty];
  1075.  };
  1076.  
  1077.  #
  1078.  # Change fonts
  1079.  #
  1080.  
  1081.  plfont = function ( font )
  1082.  {
  1083.    local (i)
  1084.  
  1085.    check_plot_object ();
  1086.    i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1087.  
  1088.    if (!exist (font)) { font = 1; }
  1089.  
  1090.    if (WIN.[P].fontld == 0)
  1091.    {
  1092.      _plfontld (1);
  1093.      WIN.[P].fontld = 1;
  1094.    }
  1095.  
  1096.    WIN.[P].font[i] = font;
  1097.    return P;
  1098.  };
  1099.  
  1100.  #
  1101.  # Change pen width
  1102.  #
  1103.  
  1104.  plwid = function ( width )
  1105.  {
  1106.    local (i)
  1107.  
  1108.    check_plot_object ();
  1109.    i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1110.  
  1111.    if (!exist (width)) { width = 1; }
  1112.    WIN.[P].width[i] = width;
  1113.    return P;
  1114.  };
  1115.  
  1116.  #
  1117.  # Place some text on the plot
  1118.  #
  1119.  
  1120.  plptex = function ( text, x , y , dx , dy , just )
  1121.  {
  1122.    if (!check_plot_object ()) {
  1123.      printf ("Must use plot() before plptex()\n");
  1124.      return 0;
  1125.    }
  1126.  
  1127.    if (!exist (x)) { x = 0; }
  1128.    if (!exist (y)) { y = 0; }
  1129.    if (!exist (dx)) { dx = abs(x)+1; }
  1130.    if (!exist (dy)) { dy = 0; }
  1131.    if (!exist (just)) { just = 0; }
  1132.  
  1133.    _plptex (x, y, dx, dy, just, text);
  1134.  };
  1135.  
  1136.  #
  1137.  # Set up the viewing altitude for 3-D plots
  1138.  #
  1139.  
  1140.  plalt = function ( ALT )
  1141.  {
  1142.    local (i)
  1143.  
  1144.    check_plot_object ();
  1145.    i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1146.    if (exist (ALT)) 
  1147.    { 
  1148.      WIN.[P].alt[i] = ALT; 
  1149.    else
  1150.      WIN.[P].alt[i] = 60;
  1151.    }
  1152.    return P;
  1153.  };
  1154.  
  1155.  #
  1156.  # Set the viewing azimuth for 3-D plots
  1157.  #
  1158.  
  1159.  plaz = function ( AZ )
  1160.  {
  1161.    local (i)
  1162.  
  1163.    check_plot_object ();
  1164.    i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1165.    if (exist (AZ)) 
  1166.    { 
  1167.      WIN.[P].az[i] = AZ; 
  1168.    else
  1169.      WIN.[P].az[i] = 45;
  1170.    }
  1171.    return P;
  1172.  };
  1173.  
  1174.  ##############################################################################
  1175.  #
  1176.  # Various internal support functions. Eventually these will be static.
  1177.  #
  1178.  ##############################################################################
  1179.  
  1180.  #
  1181.  # Find the X and Y scales for a single matrix.
  1182.  #
  1183.  
  1184.  xy_scales = function ( M, p, xmin, xmax, ymin, ymax )
  1185.  {
  1186.  
  1187.    #
  1188.    # 1st check for un-plottable data
  1189.    #
  1190.  
  1191.    if (any (any (isinf (M))))
  1192.      { error ("plot: cannot plot infs"); }
  1193.    if (any (any (isnan (M))))
  1194.      { error ("plot: cannot plot NaNs"); }
  1195.  
  1196.    if (M.nc == 1)
  1197.    {
  1198.      xmin = 1;
  1199.      xmax = M.nr;
  1200.      ymin = min (M);
  1201.      ymax = max (M);
  1202.    else
  1203.      xmin = min (M[;1]);
  1204.      xmax = max (M[;1]);
  1205.      ymin = min (min (M[;2:M.nc]));
  1206.      ymax = max (max (M[;2:M.nc]));
  1207.    }
  1208.  
  1209.    #
  1210.    # Check computed scale limits against user's
  1211.    #
  1212.  
  1213.    if (!isinf (WIN.[P].xmin[p])) { xmin = WIN.[P].xmin[p]; }
  1214.    if (!isinf (WIN.[P].xmax[p])) { xmax = WIN.[P].xmax[p]; }
  1215.    if (!isinf (WIN.[P].ymin[p])) { ymin = WIN.[P].ymin[p]; }
  1216.    if (!isinf (WIN.[P].ymax[p])) { ymax = WIN.[P].ymax[p]; }
  1217.  
  1218.    #
  1219.    # Check for potential errors
  1220.    #
  1221.  
  1222.    if (xmin == xmax) 
  1223.    { 
  1224.      xmin = xmin - 1;
  1225.      xmax = xmax + 1;
  1226.    }
  1227.  
  1228.    if (ymin == ymax)
  1229.    {
  1230.      ymin = ymin - 1;
  1231.      ymax = ymax + 1;
  1232.    }
  1233.  
  1234.    #
  1235.    # Finally, adjust if log-scales
  1236.    #
  1237.  
  1238.    if (find_char (WIN.[P].gridx[p], "l"))
  1239.    {
  1240.      if (xmin <= 0 || xmax <= 0) { error ("plot: cannot plot log <= 0"); }
  1241.      xmin = log10 (xmin);
  1242.      xmax = log10 (xmax);
  1243.    }
  1244.    if (find_char (WIN.[P].gridy[p], "l"))
  1245.    {
  1246.      if (ymin <= 0 || ymax <= 0) { error ("plot: cannot plot log <= 0"); }
  1247.      ymin = log10 (ymin);
  1248.      ymax = log10 (ymax);
  1249.    }
  1250.  
  1251.    return 1;
  1252.  };
  1253.  
  1254.  #
  1255.  # Find the X, Y and Z scales for a single matrix.
  1256.  #
  1257.  
  1258.  xyz_scales = function ( L, p, xmin, xmax, ymin, ymax, zmin, zmax )
  1259.  {
  1260.    # X - scale
  1261.    if (any (any (isinf (L.x))))
  1262.      { error ("plot3: cannot plot infs"); }
  1263.    if (any (any (isnan (L.x))))
  1264.      { error ("plot3: cannot plot NaNs"); }
  1265.    
  1266.    xmin = min (real (L.x));
  1267.    xmax = max (real (L.x));
  1268.  
  1269.    # Y - scale
  1270.    if (any (any (isinf (L.y))))
  1271.      { error ("plot3: cannot plot infs"); }
  1272.    if (any (any (isnan (L.y))))
  1273.      { error ("plot3: cannot plot NaNs"); }
  1274.    
  1275.    ymin = min (real (L.y));
  1276.    ymax = max (real (L.y));
  1277.  
  1278.    # Z - scale
  1279.    if (any (any (isinf (L.z))))
  1280.      { error ("plot3: cannot plot infs"); }
  1281.    if (any (any (isnan (L.z))))
  1282.      { error ("plot3: cannot plot NaNs"); }
  1283.  
  1284.    zmin = min (min (real (L.z)));
  1285.    zmax = max (max (real (L.z)));
  1286.  
  1287.    #
  1288.    # Check computed scale limits against user's
  1289.    #
  1290.  
  1291.    if (!isinf (WIN.[P].xmin[p])) { xmin = WIN.[P].xmin[p]; }
  1292.    if (!isinf (WIN.[P].xmax[p])) { xmax = WIN.[P].xmax[p]; }
  1293.    if (!isinf (WIN.[P].ymin[p])) { ymin = WIN.[P].ymin[p]; }
  1294.    if (!isinf (WIN.[P].ymax[p])) { ymax = WIN.[P].ymax[p]; }
  1295.    if (!isinf (WIN.[P].zmin[p])) { zmin = WIN.[P].zmin[p]; }
  1296.    if (!isinf (WIN.[P].zmax[p])) { zmax = WIN.[P].zmax[p]; }
  1297.  
  1298.    return 1;
  1299.  };
  1300.  
  1301.  #
  1302.  # Find the X and Y scales for a list of matrices
  1303.  #
  1304.  
  1305.  list_scales = function ( data, p, Xmin, Xmax, Ymin, Ymax )
  1306.  {
  1307.    local (M, i, xmin, xmax, ymin, ymax, once)
  1308.    once = 1;
  1309.  
  1310.    for (i in members (data))
  1311.    {
  1312.      M = real (data.[i]);
  1313.      if (class (M) != "num") { continue; }
  1314.  
  1315.      #
  1316.      # 1st check for un-plottable data
  1317.      #
  1318.  
  1319.      if (any (any (isinf (M))))
  1320.        { error ("plot: cannot plot infs"); }
  1321.      if (any (any (isnan (M))))
  1322.        { error ("plot: cannot plot NaNs"); }
  1323.  
  1324.      if (M.nc == 1)
  1325.      {
  1326.        xmin = 1;
  1327.        xmax = M.nr;
  1328.        ymin = min (M);
  1329.        ymax = max (M);
  1330.      else
  1331.        xmin = min (M[;1]);
  1332.        xmax = max (M[;1]);
  1333.        ymin = min (min (M[;2:M.nc]));
  1334.        ymax = max (max (M[;2:M.nc]));
  1335.      }
  1336.      if (once) { 
  1337.        Xmin = xmin; Xmax = xmax; Ymin = ymin; Ymax = ymax; 
  1338.        once = 0; 
  1339.      }
  1340.      if (xmin < Xmin) { Xmin = xmin; }
  1341.      if (xmax > Xmax) { Xmax = xmax; }
  1342.      if (ymin < Ymin) { Ymin = ymin; }
  1343.      if (ymax > Ymax) { Ymax = ymax; }
  1344.    }
  1345.  
  1346.    #
  1347.    # Check computed scale limits against user's
  1348.    #
  1349.  
  1350.    if (!isinf (WIN.[P].xmin[p])) { Xmin = WIN.[P].xmin[p]; }
  1351.    if (!isinf (WIN.[P].xmax[p])) { Xmax = WIN.[P].xmax[p]; }
  1352.    if (!isinf (WIN.[P].ymin[p])) { Ymin = WIN.[P].ymin[p]; }
  1353.    if (!isinf (WIN.[P].ymax[p])) { Ymax = WIN.[P].ymax[p]; }
  1354.  
  1355.    #
  1356.    # Finally, adjust if log-scales
  1357.    #
  1358.  
  1359.    if (find_char (WIN.[P].gridx[p], "l"))
  1360.    {
  1361.      if (Xmin <= 0 || Xmax <= 0) { error ("plot: cannot plot log x <= 0"); }
  1362.      Xmin = log10 (Xmin);
  1363.      Xmax = log10 (Xmax);
  1364.    }
  1365.    if (find_char (WIN.[P].gridy[p], "l"))
  1366.    {
  1367.      if (Ymin <= 0 || Ymax <= 0) { error ("plot: cannot plot log y <= 0"); }
  1368.      Ymin = log10 (Ymin);
  1369.      Ymax = log10 (Ymax);
  1370.    }
  1371.  
  1372.    return 1;
  1373.  };
  1374.    
  1375.  #
  1376.  # Find the maximum number of elements in a bin for a single 
  1377.  # column matrix.
  1378.  #
  1379.  
  1380.  hist_scales = function ( data, nbin )
  1381.  {
  1382.    local (i, binval, dmin, dmax, dbin)
  1383.  
  1384.    dmin = min (real (data));
  1385.    dmax = max (real (data));
  1386.    dbin = linspace (dmin, dmax, nbin+1);
  1387.    binval = zeros (nbin, 1);
  1388.  
  1389.    for (i in 1:nbin)
  1390.    {
  1391.      binval[i] = length (find (data >= dbin[i] && data < dbin[i+1]));
  1392.    }
  1393.  
  1394.    return max (binval);
  1395.  };
  1396.  
  1397.  #
  1398.  # Plot the columns of a matrix (core function)
  1399.  #
  1400.  # Notes: This is the core function for plotting a matrix. If the
  1401.  # matrix is a single column, then the matrix elements are plotted
  1402.  # versus the row numbers. If it is a multi-column matrix, then
  1403.  # columns 2:N are plotted versus column 1.
  1404.  #
  1405.  # p, K, k and l are indices for plot features.
  1406.  # p: the current plot index (the plot #)
  1407.  # K: usually 0. This index is used to start of the line style and
  1408.  # color index (k = color index, l = line-style index). This is mostly
  1409.  # used by plot_list, which may call plot_matrix repeatedly.
  1410.  # k: the line color index. This value determines the line color used
  1411.  # for each column of data. If K = 0, then k goes like 2:14, then
  1412.  # flops back to 1:14.
  1413.  # l: the line style inex. This value determines the line style used
  1414.  # for each column of data - not the line-type (points, or lines). If
  1415.  # K = 0, then l goes like 2:8, then flops back to 1:8.
  1416.  #
  1417.  
  1418.  plot_matrix = function ( M, p, K, xmin, xmax, ymin, ymax, v )
  1419.  {
  1420.    local (ans, i, k, l, np, x, y, xl, yl, desc)
  1421.  
  1422.    np = M.nr;
  1423.   
  1424.    if (M.nc == 1)
  1425.    {
  1426.      x = 1:M.nr;
  1427.      y = real (M);
  1428.      k = mod (1+K, 14) + 1;
  1429.      l = mod (1+K, 8) + 1;
  1430.  
  1431.      if (find_char (WIN.[P].gridx[p], "l"))
  1432.        { x = log10 (x); }
  1433.      if (find_char (WIN.[P].gridy[p], "l"))
  1434.        { y = log10 (y); }
  1435.  
  1436.      _plcol (WIN.[P].color[p;k]);
  1437.      _pllsty (WIN.[P].lstyle[p;l]);
  1438.  
  1439.      if (get_style (WIN.[P].style.[p], k-1) == "line") 
  1440.      {
  1441.        _plline (M.nr, x, y);
  1442.      else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  1443.        _plpoin (M.nr, x, y, WIN.[P].pstyle[p]+k);
  1444.      else if (get_style (WIN.[P].style.[p], k-1) == "line-point") {
  1445.        _plline (M.nr, x, y);
  1446.        _plpoin (M.nr, x, y, WIN.[P].pstyle[p]+k);
  1447.      else {
  1448.        _plline (M.nr, x, y);
  1449.      }}}}
  1450.  
  1451.      #
  1452.      # Now do the legend 
  1453.      #
  1454.  
  1455.      if (!any (any (isinf (WIN.[P].desc.[p]))))
  1456.      {
  1457.        # Use the default if necessary
  1458.        if (WIN.[P].desc.[p][1] == "default") 
  1459.        {
  1460.          desc = "c1";
  1461.        else if (WIN.[P].desc.[p].n == 1) {
  1462.          desc = WIN.[P].desc.[p][1];
  1463.        else
  1464.          # Not sure what to do, user has messed up.
  1465.          desc = "";
  1466.        }}
  1467.              
  1468.        v = v - (ymax-ymin)/11;
  1469.        xl = (xmax-xmin)*[10.5/12, 11/12, 11.5/12]' + xmin;
  1470.        yl = [v, v, v]' + ymin;
  1471.  
  1472.        if (get_style (WIN.[P].style.[p], k-1) == "line") 
  1473.        {
  1474.          _plline (3, xl, yl);
  1475.        else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  1476.          _plpoin (3, xl, yl, WIN.[P].pstyle[p]+k);
  1477.        else if (get_style (WIN.[P].style.[p]) == "line-point") {
  1478.          _plline (3, xl, yl);
  1479.          _plpoin (3, xl, yl, WIN.[P].pstyle[p]+k);
  1480.        }}}
  1481.  
  1482.        plptex(desc, xl[1]-(xmax-xmin)/25, yl[3], , , 1);
  1483.  
  1484.      }
  1485.  
  1486.    else
  1487.  
  1488.      #
  1489.      # Check for large column dimension
  1490.      #
  1491.  
  1492.      if (M.nc > 3*M.nr)
  1493.      {
  1494.        printf (" Plot %i columns and %i rows, are you sure (y/n) ? "...
  1495.                , M.nc, M.nr);
  1496.        ans = getline ("stdin");
  1497.        if (ans.[1] != "y") { return -1; }
  1498.      }
  1499.  
  1500.      for (i in 2:M.nc)
  1501.      {
  1502.        x = real (M[;1]);
  1503.        y = real (M[;i]);
  1504.        if (find_char (WIN.[P].gridx[p], "l"))
  1505.          { x = log10 (x); }
  1506.        if (find_char (WIN.[P].gridy[p], "l"))
  1507.          { y = log10 (y); }
  1508.  
  1509.        k = mod (i-1 + K, 14) + 1;
  1510.        l = mod (i-1 + K, 8) + 1;
  1511.  
  1512.        _plcol (WIN.[P].color[p;k]);
  1513.        _pllsty (WIN.[P].lstyle[p;l]);
  1514.  
  1515.        if (get_style (WIN.[P].style.[p], k-1) == "line") 
  1516.        {
  1517.          _plline (np, x, y);
  1518.        else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  1519.          _plpoin (np, x, y, WIN.[P].pstyle[p]+k);
  1520.        else if (get_style (WIN.[P].style.[p], k-1) == "line-point") {
  1521.          _plline (np, x, y);
  1522.          _plpoin (np, x, y, WIN.[P].pstyle[p]+k);
  1523.        else {
  1524.          _plline (np, x, y);
  1525.        }}}}
  1526.  
  1527.        #
  1528.        # Now do the legend 
  1529.        #
  1530.  
  1531.        if (!any (any (isinf (WIN.[P].desc.[p]))))
  1532.        {
  1533.          # Use the default if necessary
  1534.          if (WIN.[P].desc.[p][1] == "default") 
  1535.          {
  1536.            desc = "c" + num2str (i);
  1537.          else if (WIN.[P].desc.[p].n >= i-1) {
  1538.            desc = WIN.[P].desc.[p][i-1];
  1539.          else
  1540.            # Not sure what to do, user has messed up.
  1541.            desc = "";
  1542.          }}
  1543.              
  1544.          v = v - (ymax-ymin)/11;
  1545.          xl = (xmax-xmin)*[10.5/12, 11/12, 11.5/12]' + xmin;
  1546.          yl = [v, v, v]' + ymin;
  1547.  
  1548.          if (get_style (WIN.[P].style.[p], k-1) == "line") 
  1549.          {
  1550.            _plline (3, xl, yl);
  1551.          else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  1552.            _plpoin (3, xl, yl, WIN.[P].pstyle[p]+k);
  1553.          else if (get_style (WIN.[P].style.[p]) == "line-point") {
  1554.            _plline (3, xl, yl);
  1555.            _plpoin (3, xl, yl, WIN.[P].pstyle[p]+k);
  1556.          }}}
  1557.  
  1558.          plptex(desc, xl[1]-(xmax-xmin)/25, yl[3], , , 1);
  1559.  
  1560.        }
  1561.      }
  1562.    }
  1563.  
  1564.   return k;
  1565.  };
  1566.  
  1567.  #
  1568.  # Plot all of the matrices in a list on the same plot
  1569.  #
  1570.  
  1571.  plot_list = function ( L , p, xmin, xmax, ymin, ymax )
  1572.  {
  1573.    local (M, i, k, v)
  1574.    k = 0;
  1575.    v = ymax - ymin;
  1576.    for (i in members (L))
  1577.    {
  1578.      M = L.[i];
  1579.      if (class (M) != "num") { continue; }
  1580.      if ((k = plot_matrix (M, p, k, xmin, xmax, ymin, ymax, v)) < 0) { return k; }
  1581.    }
  1582.    return 1;
  1583.  };
  1584.  
  1585.  #
  1586.  # Check the elements of LIST.
  1587.  # LIST must contain elements `x', `y',
  1588.  # and `z'
  1589.  #
  1590.  
  1591.  check_3d_list = function ( LIST )
  1592.  {
  1593.    #
  1594.    # Check existence and types
  1595.    #
  1596.  
  1597.    if (class (LIST) != "list") {
  1598.      error ("plot3: argument must be a list");
  1599.    }
  1600.    if (!exist (LIST.x)) {
  1601.      error ("plot3: arg must contain `x' member");
  1602.    else if (class (LIST.x) != "num") {
  1603.      error ("plot3: x must be numeric");
  1604.    }}
  1605.    if (!exist (LIST.y)) {
  1606.      error ("plot3: arg must contain `y' member");
  1607.    else if (class (LIST.y) != "num") {
  1608.      error ("plot3: y must be numeric");
  1609.    }}
  1610.    if (!exist (LIST.z)) {
  1611.      error ("plot3: arg must contain `z' member");
  1612.    else if (class (LIST.z) != "num") {
  1613.      error ("plot3: z must be numeric");
  1614.    }}
  1615.  
  1616.    #
  1617.    # Check sizes
  1618.    #
  1619.  
  1620.    if (LIST.x.n != LIST.z.nr) {
  1621.      error ("plot3: x.n != z.nr");
  1622.    }
  1623.  
  1624.    if (LIST.y.n != LIST.z.nc) {
  1625.      error ("plot3: y.n != z.nc");
  1626.    }
  1627.  
  1628.  };
  1629.  
  1630.   find_char = function ( str , char )
  1631.   {
  1632.     local (i, tmp)
  1633.  
  1634.     tmp = strsplt (str);
  1635.     for (i in 1:tmp.n)
  1636.     {
  1637.       if (tmp[i] == char) 
  1638.       {
  1639.         return i;
  1640.       }
  1641.     }
  1642.     return 0;
  1643.   };
  1644.  
  1645.  plhistx = function ( M , nbin )
  1646.  {
  1647.    local (i, j, k, l, dbin, np, p, binval, xt, yt, v, desc)
  1648.  
  1649.    check_plot_object ();
  1650.  
  1651.    if (!exist (nbin)) { nbin = 10; }
  1652.  
  1653.    p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  1654.    np = M.nr;
  1655.  
  1656.    # Compute max/min values of data
  1657.  
  1658.    ymin = min (min(real (M)));
  1659.    ymax = max (max(real (M)));
  1660.  
  1661.    #
  1662.    # Check computed scale limits against user's
  1663.    #
  1664.  
  1665.    if (!isinf (WIN.[P].ymin[p])) { ymin = WIN.[P].ymin[p]; }
  1666.    if (!isinf (WIN.[P].ymax[p])) { ymax = WIN.[P].ymax[p]; }
  1667.  
  1668.    _plgra ();
  1669.    _plcol (15);
  1670.    _plfont (WIN.[P].font[p]);
  1671.    _plwid (WIN.[P].width[p]);
  1672.  
  1673.    dbin = (linspace (ymin, ymax, nbin+1))';
  1674.    for (j in 1:M.nc) {
  1675.      // counting
  1676.      for (i in 1:nbin) {
  1677.        binval[i;j] = length (find (M[;j] >= dbin[i] && M[;j] < dbin[i+1]));
  1678.      }
  1679.    }
  1680.  
  1681.    _pladv (0);
  1682.    _plvsta ();
  1683.    xmin = 0;
  1684.    xmax =  max(max(binval));
  1685.    _plwind (ymin, ymax, xmin, xmax);
  1686.    _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  1687.    dbin = (linspace (ymin, ymax, nbin))';
  1688.  
  1689.    v = xmax;
  1690.    for (i in 1:M.nc)
  1691.    {
  1692.      k = mod (i, 14) + 1;
  1693.      l = mod (i,  8) + 1;
  1694.      _plcol (WIN.[P].color[p;k]);
  1695.      _pllsty (WIN.[P].lstyle[p;l]);
  1696.  
  1697.      if (get_style (WIN.[P].style.[p], k-1) == "line") 
  1698.      {
  1699.        _plline (nbin, dbin, binval[;i]);
  1700.      else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  1701.        _plpoin (nbin, dbin, binval[;i], WIN.[P].pstyle[p]+k);
  1702.      else if (get_style (WIN.[P].style.[p], k-1) == "line-point") {
  1703.        _plline (nbin, dbin, binval[;i]);
  1704.        _plpoin (nbin, dbin, binval[;i], WIN.[P].pstyle[p]+k);     
  1705.      }}}
  1706.  
  1707.      // write legend around upper-right corner.
  1708.      // it is better to have user to choose location for legend.
  1709.  
  1710.      if (!any (any (isinf (WIN.[P].desc.[p]))))
  1711.      {
  1712.        # Use the default if necessary
  1713.        if (WIN.[P].desc.[p][1] == "default") 
  1714.        {
  1715.          desc = "c"+num2str(i);
  1716.        else if (WIN.[P].desc.[p].n >= i) {
  1717.          desc = WIN.[P].desc.[p][i];
  1718.        else
  1719.          # Not sure what to do, user has messed up.
  1720.          desc = "";
  1721.        }}
  1722.  
  1723.        v = v - (xmax)/11;
  1724.        xt = (ymax-ymin)*[10.5/12, 11/12, 11.5/12]' + ymin;
  1725.        yt = [v, v, v]';
  1726.  
  1727.        if (get_style (WIN.[P].style.[p], k-1) == "line") 
  1728.        {
  1729.          _plline (3, xt, yt);
  1730.        else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  1731.          _plpoin (3, xt, yt, WIN.[P].pstyle[p]+k);
  1732.        else if (get_style (WIN.[P].style.[p]) == "line-point") {
  1733.          _plline (3, xt, yt);
  1734.          _plpoin (3, xt, yt, WIN.[P].pstyle[p]+k);
  1735.        }}}
  1736.  
  1737.        plptex(desc, xt[1]-(ymax-ymin)/25, yt[3], , , 1);
  1738.      }
  1739.    }
  1740.  
  1741.    _plcol (15);
  1742.    _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);  
  1743.    _plflush ();
  1744.    _pltext ();
  1745.  
  1746.    #
  1747.    # Increment the plot no. so that next time
  1748.    # we use the correct settings.
  1749.    #
  1750.  
  1751.    WIN.[P].subplot = WIN.[P].subplot + 1;
  1752.  
  1753.    return 1;
  1754.  };
  1755.  
  1756.  #
  1757.  # Create a legend in the current plot window
  1758.  #
  1759.  # if pobj.desc.[p] = inf()        no legend
  1760.  # if pobj.desc.[p] = "default"        default ("c1", "c2", ...)
  1761.  # if pobj.desc.[p] = "string"        use "string" as description
  1762.  #
  1763.  
  1764.  #
  1765.  # Set the current plot legend string
  1766.  #
  1767.  plegend = function ( LEGEND )
  1768.  {
  1769.    local (p)
  1770.  
  1771.    check_plot_object ();
  1772.  
  1773.    p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  1774.  
  1775.    if (!exist (LEGEND)) 
  1776.    {
  1777.      WIN.[P].desc.[p] = inf();
  1778.      return P;
  1779.    }
  1780.  
  1781.    if (class (LEGEND) == "string")
  1782.    {
  1783.      WIN.[P].desc.[p] = LEGEND;
  1784.    }
  1785.  
  1786.    return P;
  1787.  };
  1788.  
  1789.  #
  1790.  # error bar plot
  1791.  #
  1792.  
  1793.  plerry = function (x, y, y_low, y_high)
  1794.  {
  1795.      local (hscale, xmin, xmax, ymin, ymax, i, p)
  1796.   
  1797.      check_plot_object ();
  1798.  
  1799.      p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  1800.      WIN.[P].desc.[p] = inf(); // use own legend
  1801.      
  1802.      if (x.nr != y.nr || x.nr != y_low.nr || x.nr != y_high.nr) {
  1803.        error(" Size inconsistent in plerry.");
  1804.      }
  1805.      _plgra ();
  1806.      _plcol (15);
  1807.      _pllsty (1);
  1808.      _plfont (WIN.[P].font[p]);
  1809.      _plwid (WIN.[P].width[p]);
  1810.      xy_scales ( real([x,y,y_low,y_high]), p, xmin, xmax, ymin, ymax );
  1811.  
  1812.      _pladv (0);
  1813.      _plvsta ();
  1814.      _plwind (xmin, xmax, ymin, ymax);
  1815.      _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  1816.      if (plot_matrix ( [x,y], p, 0, xmin, xmax, ymin, ymax, ymax-ymin ) < 0) { return -1; }
  1817.      _plcol (9);
  1818.      _plerry(x.nr, x, y_low, y_high);
  1819.      _plcol (15);
  1820.      _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);  
  1821.      _plflush ();
  1822.      _pltext ();
  1823.  
  1824.      #
  1825.      # Increment the plot no. so that next time
  1826.      # we use the correct settings.
  1827.      #
  1828.  
  1829.      WIN.[P].subplot = WIN.[P].subplot + 1;
  1830.      return P;      
  1831.  };
  1832.